package Data_Flow;

import Data_IO.data_json.Json_Traveller;
import Data_Structure.DataType.CreditCardAccount;
import Data_Structure.DataType.MyFlight;
import Data_Structure.DataType.TargetFlight;
import Data_Structure.DataType.Traveller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static Data_Flow.DataStandardIO.*;

/**
 * The class which contains static methods for extracting data and saving data.
 *
 * @author Yibai Jiang
 * @author Shunhao Yan
 * @version 2.0
 * @since 27 April 2022
 */
public class DataExplorer {

    /**
     * The idx of target traveller in Json file.
     */
    static int idx_traveller = 0;

    /**
     * The idx of target creditCardAccount in Json file.
     */
    static int idx_creditCardAccount = 0;

    /**
     * The idx of target targetFlight in Json file.
     */
    static int idx_targetFlight = 0;

    /**
     * The idx of target MyFlight which is owned by the target traveller in Json file.
     */
    static String stridx_MyFlight = "";

    /**
     * The number used to judge whether the save methods are executed in correct order or not.
     */
    static int readCount = 0;

    /**
     * Return the requested traveller with the type of JavaObject.
     *
     * @param bookingNumber the booking number
     * @return The requested traveller with specific bookingNumber.
     * @throws IOException the io exception
     */
    static public Traveller readTraveller_bookingNumber(String bookingNumber) throws IOException {
        DataStandardIO.readTraveller();
        idx_traveller = DataStandardIO.json_traveller.returnIdx(bookingNumber);
        stridx_MyFlight = DataStandardIO.json_traveller.returnMyFlightInx(bookingNumber);
        return JSON.toJavaObject(DataStandardIO.json_traveller.searchBookingNumber_returnTraveller(bookingNumber), Traveller.class);
    }

    /**
     * Return the requested traveller with the type of JavaObject.
     *
     * @param personID the booking number
     * @return The requested traveller with specific personID.
     * @throws IOException the io exception
     */
    static public Traveller readTraveller_PersonID(String personID) throws IOException {
        DataStandardIO.readTraveller();
        idx_traveller = DataStandardIO.json_traveller.returnIdx(personID);
        return JSON.toJavaObject(DataStandardIO.json_traveller.searchPersonID_returnTraveller(personID), Traveller.class);
    }

    /**
     * Return the requested myFlight with the type of JavaObject.
     *
     * @param bookingNumber the booking number
     * @return The requested myFlight which is owned by traveller with specific bookingNumber.
     * @throws IOException the io exception
     */
    static public MyFlight readAndSetMyFlight(String bookingNumber) throws IOException {
        readCount++;
        return JSON.toJavaObject(DataStandardIO.json_traveller.searchBookingNumber_returnMyFlight(bookingNumber), MyFlight.class);
    }

    /**
     * Return the requested myFlight (read only) with the type of JavaObject.
     *
     * @param bookingNumber the booking number
     * @return The requested myFlight (read only) which is owned by traveller with specific bookingNumber.
     * @throws IOException the io exception
     */
    static public MyFlight readMyFlight(String bookingNumber) throws IOException {
        return JSON.toJavaObject(DataStandardIO.json_traveller.searchBookingNumber_returnMyFlight(bookingNumber), MyFlight.class);
    }

    /**
     * Return the requested Traveller List
     *
     * @param flightID the flight ID
     * @return The requested Traveller List
     * @throws IOException the io exception
     */
    static public List<Traveller> readTraveller_staff(String flightID) throws IOException {
        DataStandardIO.readTraveller();
        List<Traveller> list = new ArrayList<>();
        list = JSON.parseArray(DataStandardIO.json_traveller.searchFlightID_returnTraveller(flightID).toJSONString(), Traveller.class);
        return list;
    }

    /**
     * Return the requested creditCardAccount with the type of JavaObject.
     *
     * @param personID the person id
     * @return The requested creditCardAccount with specific personID.
     * @throws IOException the io exception
     */
    static public CreditCardAccount readCreditCardAccount(String personID) throws IOException {
        DataStandardIO.readCreditCardAccount();
        idx_creditCardAccount = DataStandardIO.json_creditCardAccount.returnIdx(personID);
        return JSON.toJavaObject(DataStandardIO.json_creditCardAccount.searchJson_returnCreditCardAccount(personID), CreditCardAccount.class);
    }

    /**
     * Return the requested targetFlight with the type of JavaObject.
     *
     * @param flightID the flight id
     * @return The requested targetFlight with specific flightID.
     * @throws IOException the io exception
     */
    static public TargetFlight readTargetFlight(String flightID) throws IOException {
        DataStandardIO.readTargetFlight();
        idx_targetFlight = DataStandardIO.json_targetFlight.returnIdx(flightID);
        return JSON.toJavaObject(DataStandardIO.json_targetFlight.searchJson_returnTargetFlight(flightID), TargetFlight.class);
    }

    /**
     * Save the changes in typical traveller.
     *
     * @param traveller the traveller
     * @return Whether the order of the save methods correct or not.
     * @throws IOException the io exception
     */
    static public boolean saveTraveller(Traveller traveller) throws IOException {
        if (DataExplorer.readCount != 0){
            throw new IOException("Still exit some myFlight instances haven't been saved !" + readCount);
        }

        JSONObject JsonOb = (JSONObject) JSON.toJSON(traveller);
        JSONArray jsonArray = DataStandardIO.json_traveller.getJsonarray();

        JSONObject jsonObject = jsonArray.getJSONObject(idx_traveller).getJSONObject("flight");

        jsonArray.remove(idx_traveller);
        jsonArray.add(idx_traveller,JsonOb);

        jsonArray.getJSONObject(idx_traveller).replace("flight",jsonObject);

        DataStandardIO.json_traveller.setJsonarray(jsonArray);

        updateTraveller();
        return true;
    }

    /**
     * Save the changes in typical myFlight.
     *
     * @param myFlight the my flight
     * @throws IOException the io exception
     */
    static public void saveMyFlight(MyFlight myFlight) throws IOException {
        DataExplorer.readCount--;
        JSONObject JsonOb = (JSONObject) JSON.toJSON(myFlight);
        JSONArray jsonArray = DataStandardIO.json_traveller.getJsonarray();
        jsonArray.getJSONObject(idx_traveller).getJSONObject("flight").replace(stridx_MyFlight,JsonOb);
        DataStandardIO.json_traveller.setJsonarray(jsonArray);
    }

    /**
     * Save the changes in typical creditCardAccount.
     *
     * @param creditCardAccount the credit card account
     * @throws IOException the io exception
     */
    static public void saveCreditCardAccount(CreditCardAccount creditCardAccount) throws IOException {
        JSONObject JsonOb = (JSONObject) JSON.toJSON(creditCardAccount);
        JSONArray jsonArray = DataStandardIO.json_creditCardAccount.getJsonarray();
        jsonArray.remove(idx_creditCardAccount);
        jsonArray.add(idx_creditCardAccount,JsonOb);
        DataStandardIO.json_creditCardAccount.setJsonarray(jsonArray);
        updateCreditCardAccount();
    }

    /**
     * Save the changes in typical targetFlight.
     *
     * @param targetFlight the target flight
     * @throws IOException the io exception
     */
    static public void saveTargetFlight(TargetFlight targetFlight) throws IOException {
        JSONObject JsonOb = (JSONObject) JSON.toJSON(targetFlight);
        JSONArray jsonArray = DataStandardIO.json_targetFlight.getJsonarray();
        jsonArray.remove(idx_targetFlight);
        jsonArray.add(idx_targetFlight,JsonOb);
        DataStandardIO.json_targetFlight.setJsonarray(jsonArray);
        updateTargetFlight();
    }

    /**
     * Test func.
     */
    @Test
    public void TestFunc() throws IOException {
        DataStandardIO.readInitialize();
        try {
            List<Traveller> list = new ArrayList<Traveller>();
            list = DataExplorer.readTraveller_staff("111111");
            System.out.println(list);
//            Traveller traveller = DataExplorer.readTraveller_bookingNumber("222222");
//            System.out.println(traveller.getFullName());

        } catch (Exception e) {
            e.printStackTrace();
        }

//        MyFlight myFlight = DataExplorer.readAndSetMyFlight("222222");
//        System.out.println(myFlight.getMyCarryOnBaggage());
//
//        CreditCardAccount creditCardAccount = DataExplorer.readCreditCardAccount("11010520010201");
//        System.out.println(creditCardAccount.getCardID());
//
//        TargetFlight targetFlight = DataExplorer.readTargetFlight("200837");
//        System.out.println(targetFlight.getTargetGate());

    }
}
